package main

import(
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"github.com/spf13/pflag"
)

type selpg_args struct{
	startPage      int
	endPage        int
	inFile         string
	pageLen        int
	pageType       bool // true for -f, false for -lNumber
	outDestination string
}

//获取命令行参数
func getArgs(args *selpg_args){
	//获取参数
	pflag.IntVarP(&(args.startPage),"startPage","s",-1,"start page")
	pflag.IntVarP(&(args.endPage),"endPage","e",-1,"end page")
	pflag.IntVarP(&(args.pageLen),"pageLen","l",72,"the length of page")
	pflag.BoolVarP(&(args.pageType),"pageType","f",false,"page type")
	pflag.StringVarP(&(args.outDestination),"outDestination","d","","print destination")
	//解析参数
	pflag.Parse()
	args_left:=pflag.Args() // 其余参数
	if len(args_left) > 0 {
		args.inFile=args_left[0]
	} else {
		args.inFile=""
	}
	check_args(args)
}

//检查参数合法性
func check_args(args *selpg_args){
	if args==nil{
		fmt.Fprintf(os.Stderr,"\n[Error] Please use command 'selpg -help' to check your arguments.\n")
		os.Exit(0)
	}else if (args.startPage<0)||(args.endPage<0){
		fmt.Fprintf(os.Stderr,"\n[Error]Please input startPage and endPage number!(>=1)\n")
		os.Exit(0)
	}else if args.startPage>args.endPage{
		fmt.Fprintf(os.Stderr,"\n[Error]The startPage can not be bigger than the endPage!\n")
		os.Exit(0)
	}
	if args.pageType==false&&args.pageLen<1 {
		fmt.Fprintln(os.Stderr,"\n[Error]You should input valid page length!\n\n")
		os.Exit(0)
	}
}

//检查页号是否合理
func checkPageNum(args *selpg_args, pageCtr int) {
	if pageCtr < args.startPage {
		os.Stderr.Write([]byte("Start page is bigger than the total page num\n"))
		os.Exit(0)
	}
	if pageCtr < args.endPage {
		os.Stderr.Write([]byte("End page is bigger than the total page num\n"))
		os.Exit(0)
	}
}

func processInput(args *selpg_args){
	//读取文件
	var reader *bufio.Reader
	//若未指定文件，则读入标准文件作为输入文件
	if args.inFile=="" {
		reader=bufio.NewReader(os.Stdin)
	} else{//读入输入文件
		fileIn,err:=os.Open(args.inFile)
		defer fileIn.Close()
		if err!=nil {
			os.Stderr.Write([]byte("Open file error.\n"))
			os.Exit(0)
		}
		reader=bufio.NewReader(fileIn)
	}
	output(reader,args)
}

//根据参数类型选择输出格式
func output(reader *bufio.Reader,args *selpg_args){
	var cmd *exec.Cmd=nil
	var stdin io.WriteCloser=nil
	writer:=bufio.NewWriter(os.Stdout)
	//指定输出目的地
	if args.outDestination!="" {
		cmd=exec.Command(args.outDestination)
		var pipeErr error;
		stdin,pipeErr=cmd.StdinPipe()
		if pipeErr!=nil {
			fmt.Println(pipeErr)
			os.Exit(0)
		}
		startErr:=cmd.Start()
		if startErr!=nil {
			fmt.Println(startErr)
			os.Exit(0)
		}
	}
	//输出到命令行
	lineCtr:=0
	pageCtr:=1
	endSign:='\n'
	if args.pageType==true {
		endSign='\f'
	}
	for{
		strLine,errRead:=reader.ReadBytes(byte(endSign))
		if errRead!=nil {
			if errRead==io.EOF {
				writer.Flush()
				break
			} else{
				os.Stderr.Write([]byte("Read bytes from reader failed.\n"))
				os.Exit(0)
			}
		}
		if pageCtr>=args.startPage&&pageCtr<=args.endPage {
			_,errWrite:=writer.Write(strLine)
			if errWrite!=nil {
				fmt.Println(errWrite)
				os.Stderr.Write([]byte("Write bytes to out failed.\n"))
				os.Exit(0)
			}
			if stdin!=nil {
				_,errWrite:=stdin.Write(strLine)
				if errWrite!=nil {
					fmt.Println(errWrite)
					os.Stderr.Write([]byte("Write bytes to out failed.\n"))
					os.Exit(0)
				}
			}
		}
		if args.pageType==true {
			pageCtr++
		} else{
			lineCtr++
		}
		if args.pageType==false&&lineCtr==args.pageLen {
			lineCtr=0
			pageCtr++
		}
		if pageCtr>args.endPage {
			writer.Flush()
			break
		}
	}
	if stdin!=nil {
		stdin.Close()
	}
	if cmd!=nil {
		if err:=cmd.Wait();err!=nil {
			fmt.Println(err)
			os.Exit(0)
		}
	}
	checkPageNum(args, pageCtr)
}

func main(){
	var args selpg_args
	getArgs(&args)
	processInput(&args)
}